package com.example.fastexcel.controller;

import cn.idev.excel.EasyExcel;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel;
import cn.idev.excel.read.listener.PageReadListener;
import cn.idev.excel.write.metadata.WriteSheet;
import com.example.fastexcel.model.dto.UserExcelDTO;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.DateUtil;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.xnio.Result;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * Excel导入导出控制器
 * 使用EasyExcel实现Excel文件的导入导出功能
 */
@Slf4j
@RestController
@RequestMapping("/api/excel")
public class ExcelController {
    
    /**
     * 模拟数据库数据（实际项目中应从数据库查询）
     */
    private List<UserExcelDTO> getMockUserData() {
        List<UserExcelDTO> users = new ArrayList<>();
        
        for (int i = 1; i <= 100; i++) {
            UserExcelDTO user = new UserExcelDTO();
            user.setId((long) i);
            user.setUsername("user" + i);
            user.setRealName("用户" + i);
            user.setEmail("user" + i + "@example.com");
            user.setPhone("1380013800" + (i % 10));
            user.setAge(20 + (i % 50));
            user.setSalary(java.math.BigDecimal.valueOf(5000 + (i * 100)));
            user.setHireDate(LocalDateTime.now().minusDays(i));
            user.setStatus(i % 2 == 0 ? 1 : 0);
            users.add(user);
        }
        
        return users;
    }
    
    /**
     * 导出Excel文件（全量导出
     * 
     * @param response HTTP响应对象
     * @throws IOException IO异常
     */
    @GetMapping("/export")
    public void exportExcel(HttpServletResponse response) throws IOException {
        try {
            // 获取要导出的数据
            List<UserExcelDTO> userData = getMockUserData();
            
            // 设置响应头
            String fileName = "用户数据_" + DateUtil.format(DateUtil.date(), "yyyyMMdd_HHmmss") + ".xlsx";
            setExcelResponseHeader(response, fileName);
            
            // 使用EasyExcel写入数据
            EasyExcel.write(response.getOutputStream(), UserExcelDTO.class)
                .sheet("用户数据")
                .doWrite(userData);
                
            log.info("Excel导出成功，共导出 {} 条数据", userData.size());
            
        } catch (Exception e) {
            log.error("Excel导出失败", e);
            // 导出失败时返回错误信息
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json");
            response.getWriter().write("{\"code\":500,\"message\":\"导出失败: " + e.getMessage() + "\"}");
        }
    }
    
    /**
     * 分页导出Excel文件
     * 适用于大数据量导出，避免内存溢出
     * 
     * @param response HTTP响应对象
     * @throws IOException IO异常
     */
    @GetMapping("/export/paginated")
    public void exportExcelPaginated(HttpServletResponse response) throws IOException {
        try {
            // 设置响应头
            String fileName = "用户数据_分页_" + DateUtil.format(DateUtil.date(), "yyyyMMdd_HHmmss") + ".xlsx";
            setExcelResponseHeader(response, fileName);
            
            // 创建ExcelWriter
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), UserExcelDTO.class)
                .build();
            
            // 创建工作表
            WriteSheet writeSheet = EasyExcel.writerSheet("用户数据").build();
            
            // 分页查询并写入数据（模拟分页）
            int pageSize = 1000; // 每页1000条
            int currentPage = 0;
            List<UserExcelDTO> pageData;
            
            do {
                // 模拟分页查询（实际项目中应调用数据库分页查询）
                pageData = getMockPageData(currentPage, pageSize);
                
                if (!pageData.isEmpty()) {
                    // 写入当前页数据
                    excelWriter.write(pageData, writeSheet);
                    currentPage++;
                }
                
            } while (!pageData.isEmpty());
            
            // 关闭ExcelWriter
            excelWriter.finish();
            
            log.info("分页Excel导出成功，共导出 {} 页", currentPage);
            
        } catch (Exception e) {
            log.error("分页Excel导出失败", e);
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json");
            response.getWriter().write("{\"code\":500,\"message\":\"导出失败: " + e.getMessage() + "\"}");
        }
    }
    
    /**
     * 模拟分页数据查询
     * 
     * @param page 页码（从0开始）
     * @param size 每页大小
     * @return 分页数据
     */
    private List<UserExcelDTO> getMockPageData(int page, int size) {
        // 模拟总共10000条数据
        int totalRecords = 10000;
        int start = page * size;
        int end = Math.min(start + size, totalRecords);
        
        if (start >= totalRecords) {
            return CollUtil.newArrayList();
        }
        
        List<UserExcelDTO> pageData = new ArrayList<>();
        for (int i = start; i < end; i++) {
            UserExcelDTO user = new UserExcelDTO();
            user.setId((long) i + 1);
            user.setUsername("user" + (i + 1));
            user.setRealName("用户" + (i + 1));
            user.setEmail("user" + (i + 1) + "@example.com");
            user.setPhone("1380013800" + ((i + 1) % 10));
            user.setAge(20 + ((i + 1) % 50));
            user.setSalary(java.math.BigDecimal.valueOf(5000 + ((i + 1) * 100)));
            user.setHireDate(LocalDateTime.now().minusDays(i + 1));
            user.setStatus((i + 1) % 2 == 0 ? 1 : 0);
            pageData.add(user);
        }
        
        return pageData;
    }
    
    /**
     * Excel文件导入 https://docs.springframework.org.cn/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/multipart-forms.html
     * 
     * @param file 上传的Excel文件
     * @return 导入结果
     */
    @PostMapping("/import")
    public Result<String> importExcel(@RequestParam("file") MultipartFile file) {
        try {
            // 验证文件
            if (file.isEmpty()) {
                return Result.error("请选择要导入的Excel文件");
            }
            
            String originalFilename = file.getOriginalFilename();
            if (!originalFilename.endsWith(".xlsx") && !originalFilename.endsWith(".xls")) {
                return Result.error("请上传Excel文件（.xlsx或.xls格式）");
            }
            
            // 读取Excel文件数据
            List<UserExcelDTO> importedData = new ArrayList<>();
            
            // 使用EasyExcel读取数据
            FastExcel.read(file.getInputStream(), UserExcelDTO.class,
                new PageReadListener<UserExcelDTO>(dataList -> {
                    // 处理每一批数据（默认100条一批）
                    importedData.addAll(dataList);
                    
                    // 这里可以进行数据验证、转换、保存到数据库等操作
                    // 为了示例简单，这里只做简单处理
                    log.info("读取到 {} 条数据", dataList.size());
                }))
                .sheet()
                .doRead();
            
            // 验证导入的数据
            if (importedData.isEmpty()) {
                return Result.error("Excel文件中没有有效数据");
            }
            
            // 实际项目中，这里应该将数据保存到数据库
            // validateAndSaveData(importedData);
            
            log.info("Excel导入成功，共导入 {} 条数据", importedData.size());
            return Result.success("Excel导入成功，共导入 " + importedData.size() + " 条数据");
            
        } catch (Exception e) {
            log.error("Excel导入失败", e);
            return Result.error("Excel导入失败: " + e.getMessage());
        }
    }
    
    /**
     * 设置Excel文件下载的响应头
     * 
     * @param response HTTP响应对象
     * @param fileName 文件名
     * @throws IOException IO异常
     */
    private void setExcelResponseHeader(HttpServletResponse response, String fileName) throws IOException {
        // 设置内容类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        
        // 编码文件名（处理中文）
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8)
            .replaceAll("\\+", "%20");
        
        // 设置Content-Disposition头
        response.setHeader("Content-Disposition", 
            "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);
    }
}
